local BigNum = require "BigNum"

-------------------------------------------------------------------------------
---! 内部方法
-------------------------------------------------------------------------------
---! 查找关卡配置
local function find_stage_config(stageid)
    local configs = IMPORT_D:query("swstage")
    if not configs then
        return
    end

    local config = configs[stageid]
    if not config then
        return
    end

    return config
end

---! 查找宝箱配置
local function find_box_config(boxid)
    local configs = IMPORT_D:query("swbox")
    if not configs then
        return
    end

    local config = configs[boxid]
    if not config then
        return
    end

    return config
end

---! 获取每日刷新次数上限
local function get_refresh_max_times()
    local common_config = IMPORT_D:query("swcommon")
    if not common_config then
        return 0
    end

    return common_config.dailyRefreshTimeMax
end

---! 获取每日可看广告/分享次数上限
local function get_max_adtimes()
    local common_config = IMPORT_D:query("swcommon")
    if not common_config then
        return 0
    end

    return common_config.dailySwDungeonAddMax
end

---! 获取每日重置挑战次数上限
local function get_reset_max_times()
    local common_config = IMPORT_D:query("swcommon")
    if not common_config then
        return 0
    end

    return common_config.dailySwDungeonNum
end

---! 获取每日可水晶购买次数上限
local function get_max_buytimes()
    local common_config = IMPORT_D:query("swcommon")
    if not common_config then
        return 0
    end

    return common_config.swDungeonBuyMax
end

---! 获取下次刷新时间
local function get_refresh_time()
    local m = os.date("*t")
    m.day = m.day + (day or 1)
    m.hour = 0
    m.min = 0
    m.sec = 0
    return os.time(m)
end

---! 获取玩家当前刷新次数
local function get_refresh_times(player)
    return player:query("artifactstage", "refresh") or 0
end

---! 获取玩家当前挑战次数
local function get_fight_times(player)
    local times = player:query("artifactstage", "fight")
    if not times then
        times = player:set("artifactstage", "fight", get_reset_max_times())
    end
    return times
end

---! 获取玩家当前看广告次数
local function get_adtimes(player)
    return player:query("artifactstage", "adtimes") or 0
end

---! 获取玩家当前购买次数
local function get_diamond_times(player)
    return player:query("artifactstage", "buytimes") or 0
end

---! 随机生成当前挑战牢笼
local function random_stage_data(exclude)
    local configs = IMPORT_D:query("swstage")
    if not configs then
        return
    end

    local stars = {}
    for _, config in pairs(configs) do repeat
        if type(exclude) == "table" and exclude[config.id] then
            break
        end

        for idx, weight in ipairs(config.swRefreshWeight) do
            if weight > 0 then
                local tbl = { id = config.id, weight = weight, }
                if stars[idx] then
                    table.insert(stars[idx], tbl)
                else
                    stars[idx] = { tbl, }
                end
            end
        end
    until true end

    local stages = {}
    for idx, config in ipairs(stars) do
        local sum = 0
        for _, tbl in ipairs(config) do
            sum = sum + tbl.weight
        end

        if sum > 0 then
            local num = math.random(sum)
            for _, tbl in ipairs(config) do
                if num <= tbl.weight then
                    stages[idx] = { id = tbl.id, status = 0, stage = idx, }
                    break
                end
                num = num - tbl.weight
            end
        end
    end
    return stages
end

---! 随机生成当前奖励数值
local function random_prop_count(level, propid, swdropNum)
    local configs = IMPORT_D:query("swdrop")
    if not configs then
        return
    end

    local config = configs[level]
    if not config then
        return
    end

    if propid == GamePropIds.kGamePropIdsCopperIcon then
        return config.dropCoin * swdropNum / 100
    elseif propid == GamePropIds.kGamePropIdsDiamondsIcon then
        return config.dropDiamond * swdropNum  / 100
    elseif propid == GamePropIds.kGamePropIdsStoneIcon then
        return config.dropRock * swdropNum / 100
    end
end

---! 随机生成当前牢笼奖励
local function random_stage_reward(level, stageid)
    local config = find_stage_config(stageid)
    if not config then
        return
    end

    local sum = 0
    for _, weight in ipairs(config.swWelfareWeight) do
        sum = sum + weight
    end

    local num = math.random(sum)
    for idx, weight in ipairs(config.swWelfareWeight) do repeat
        if num > weight then
            num = num - weight
            break
        end

        local propId = config.swWelfare[idx]
        local propCount = random_prop_count(level, propId, config.swdropNum)
        if not propId or not propCount then
            break
        end

        return { propId = propId, propCount = tostring(propCount), }
    until true end
end

---! 获取当前玩家牢笼数据
local function get_stage_data(player)
    local stages = player:query("artifactstage", "stages")
    if not stages then
        stages = player:set("artifactstage", "stages", random_stage_data())
    end
    return stages
end

---! 获取玩家当前开箱数据
local function get_box_data(player)
    local boxes = player:query("artifactstage", "boxes")
    if not boxes then
        boxes = player:set("artifactstage", "boxes", {})
    end
    return boxes
end

---! 获取玩家当前挑战总星数
local function get_star_sum(player)
    return player:query("artifactstage", "stars") or 0
end

-------------------------------------------------------------------------------
---! 对外接口
-------------------------------------------------------------------------------
ARTIFACTSTAGE_D = {}

---! 初始副本信息
function ARTIFACTSTAGE_D:init_artifactstage_info(player)
end

---! 增加挑战次数
function ARTIFACTSTAGE_D:add_fight_times(player, mode)
    local common_config = IMPORT_D:query("swcommon")
    if not common_config then
        local result = {}
        result.error = 1
        player:send_packet("MSGS2CArtifactStageAdd", result)
        return
    end

    if mode == 0 then
        --[[
        local adtimes = get_adtimes(player)
        if adtimes >= get_max_adtimes() then
            local result = {}
            result.error = 1
            player:send_packet("MSGS2CArtifactStageAdd", result)
            return
        end

        ---! 记录看广告/分享次数
        player:set("artifactstage", "adtimes", adtimes + 1)

        ---! 累加挑战次数
        player:set("artifactstage", "fight", get_fight_times(player) + common_config.dailySwDungeonAdd)
        --]]
    elseif mode == 1 then
        local buytimes = get_diamond_times(player)
        if buytimes >= get_max_buytimes() then
            local result = {}
            result.error = 2
            player:send_packet("MSGS2CArtifactStageAdd", result)
            return
        end

        local count = math.floor(common_config.swDungeonBuyNum * (common_config.swDungeonBuyMul ^ buytimes))
        if player:get_currency(GamePropIds.kGamePropIdsDiamondsIcon) < count then
            local result = {}
            result.error = 3
            player:send_packet("MSGS2CArtifactStageAdd", result)
            return
        end

        ---! 扣除所需费用
        player:cost_currency(GamePropIds.kGamePropIdsDiamondsIcon, count)
        ITEM_D:send_currency_info(player)

        ---! 记录水晶购买次数
        player:set("artifactstage", "buytimes", buytimes + 1)

        ---! 累加挑战次数
        player:set("artifactstage", "fight", get_fight_times(player) + 1)
    end

    ---! 通知客户端
    local result = {}
    result.error = 0
    player:send_packet("MSGS2CArtifactStageAdd", result)

    ---! 刷新副本信息
    ARTIFACTSTAGE_D:send_artifactstage_data(player)
end

---! 通过关卡挑战
function ARTIFACTSTAGE_D:pass_stage(player, stageid, succ)
    local fight_times = get_fight_times(player)
    if fight_times <= 0 then
        local result = {}
        result.error = 1
        result.stage = stageid
        player:send_packet("MSGS2CArtifactStagePass", result)
        return
    end

    local stages = get_stage_data(player)
    local stage_data = stages[stageid]
    if not stage_data then
        local result = {}
        result.error = 2
        result.stage = stageid
        player:send_packet("MSGS2CArtifactStagePass", result)
        return
    end

    local config = find_stage_config(stage_data.id)
    if not config then
        local result = {}
        result.error = 3
        result.stage = stageid
        player:send_packet("MSGS2CArtifactStagePass", result)
        return
    end

    if stage_data.status ~= 0 then
        local result = {}
        result.error = 4
        result.stage = stageid
        player:send_packet("MSGS2CArtifactStagePass", result)
        return
    end

    if succ == 0 then
        ---! 扣除挑战次数
        player:set("artifactstage", "fight", get_fight_times(player) - 1)

        ---! 通知客户端
        local result = {}
        result.error = 0
        result.stage = stageid
        player:send_packet("MSGS2CArtifactStagePass", result)

        ---! 刷新副本信息
        ARTIFACTSTAGE_D:send_artifactstage_data(player)
        return
    end

    ---! 获取关卡奖励信息
    local prop = player:query("artifactstage", "cache", stageid)
    if not prop then
        local reward = random_stage_reward(player:get_level(), stage_data.id)
        if not reward then
            local result = {}
            result.error = 5
            result.stage = stageid
            player:send_packet("MSGS2CArtifactStagePass", result)
            return
        end

        prop = player:set("artifactstage", "cache", stageid, reward)
    end

    ---! 通知客户端
    local result = {}
    result.error = 0
    result.stage = stageid
    result.prop = { propId = prop.propId, propCount = INVENTORY_D:get_currency_show_count(player, prop.propId, prop.propCount), }
    player:send_packet("MSGS2CArtifactStagePass", result)
end

---! 领取通关奖励
function ARTIFACTSTAGE_D:draw_stage(player, stageid, isdouble)
    local stages = get_stage_data(player)
    local stage_data = stages[stageid]
    if not stage_data then
        local result = {}
        result.error = 1
        result.stage = stageid
        player:send_packet("MSGS2CArtifactStageDraw", result)
        return
    end

    local config = find_stage_config(stage_data.id)
    if not config then
        local result = {}
        result.error = 2
        result.stage = stageid
        player:send_packet("MSGS2CArtifactStageDraw", result)
        return
    end

    if stage_data.status ~= 0 then
        local result = {}
        result.error = 3
        result.stage = stageid
        player:send_packet("MSGS2CArtifactStageDraw", result)
        return
    end

    ---! 获取关卡奖励信息
    local prop = player:query("artifactstage", "cache", stageid)
    if not prop then
        local result = {}
        result.error = 4
        player:send_packet("MSGS2CArtifactStageDraw", result)
        return
    end

    ---! 扣除挑战次数
    player:set("artifactstage", "fight", get_fight_times(player) - 1)

    ---! 累加挑战星数
    player:set("artifactstage", "stars", get_star_sum(player) + config.swStar)

    ---! 清理奖励信息
    player:delete("artifactstage", "cache", stageid)

    ---! 修改关卡状态
    stage_data.status = 1

    ---! 给与关卡奖励
    if isdouble ~= 0 then
        prop.propCount = BigNum.new(prop.propCount) * 2
    end
    player:add_currency(prop.propId, prop.propCount)
    ITEM_D:send_currency_info(player)

    local result = {}
    result.error = 0
    result.isDouble = isdouble
    result.prop = { propId = prop.propId, propCount = INVENTORY_D:get_currency_show_count(player, prop.propId, prop.propCount), }
    player:send_packet("MSGS2CArtifactStageDraw", result)

    ---! 刷新副本信息
    ARTIFACTSTAGE_D:send_artifactstage_data(player)
end

---! 领取宝箱奖励
function ARTIFACTSTAGE_D:draw_box(player, boxid, isdouble)
    local config = find_box_config(boxid)
    if not config then
        local result = {}
        result.error = 1
        player:send_packet("MSGS2CArtifactStageBoxDraw", result)
        return
    end

    local star_sum = get_star_sum(player)
    if star_sum < config.boxStar then
        local result = {}
        result.error = 2
        player:send_packet("MSGS2CArtifactStageBoxDraw", result)
        return
    end

    local boxes = get_box_data(player)
    for _, box in ipairs(boxes) do
        if box.id == boxid and box.status == 1 then
            local result = {}
            result.error = 3
            player:send_packet("MSGS2CArtifactStageBoxDraw", result)
            return
        end
    end

    ---! 记录当前宝箱已领取
    table.insert(boxes, { id = boxid, status = 1, })

    ---! 获取当前宝箱奖励
    local prop = { propId = config.rewardId, propCount = config.rewardNum, }
    if isdouble ~= 0 then
        prop.propCount = prop.propCount * 2
    end

    ---! 发送当前宝箱奖励
    player:add_currency(prop.propId, prop.propCount)
    ITEM_D:send_currency_info(player)

    ---! 通知宝箱奖励领取成功
    local result = {}
    result.error = 0
    result.id = boxid
    result.isDouble = isdouble
    result.prop = prop
    player:send_packet("MSGS2CArtifactStageBoxDraw", result)

    ---! 刷新副本信息
    ARTIFACTSTAGE_D:send_artifactstage_data(player)
end

---! 刷新副本信息
function ARTIFACTSTAGE_D:refresh_artifactstage_data(player)
    local common_config = IMPORT_D:query("swcommon")
    if not common_config then
        local result = {}
        result.error = 1
        player:send_packet("MSGS2CArtifactStageRefresh", result)
        return
    end

    local times = get_refresh_times(player)
    if times >= get_refresh_max_times() then
        local result = {}
        result.error = 2
        player:send_packet("MSGS2CArtifactStageRefresh", result)
        return
    end

    if common_config.refreshCostItem > 0 and common_config.refreshCostItemNum > 0 then
        local propId = common_config.refreshCostItem
        local propCount = math.floor(common_config.refreshCostItemNum * (common_config.refreshCostItemNumUp ^ times))
        if player:get_currency(propId) < propCount then
            local result = {}
            result.error = 3
            player:send_packet("MSGS2CArtifactStageRefresh", result)
            return
        end

        ---! 扣除指定道具
        player:cost_currency(propId, propCount)
        ITEM_D:send_currency_info(player)
    end

    ---! 累加刷新次数
    player:set("artifactstage", "refresh", times + 1)

    ---! 清理奖励缓存
    player:delete("artifactstage", "cache")

    ---! 刷新当前关卡
    local exclude = {}
    for _, stage in ipairs(get_stage_data(player)) do
        exclude[stage.id] = true
    end
    player:set("artifactstage", "stages", random_stage_data(exclude))

    ---! 通知刷新成功
    local result = {}
    result.error = 0
    player:send_packet("MSGS2CArtifactStageRefresh", result)

    ---! 刷新副本信息
    ARTIFACTSTAGE_D:send_artifactstage_data(player)
end

---! 发送副本信息
function ARTIFACTSTAGE_D:send_artifactstage_data(player)
    local result = {}
    result.stages = get_stage_data(player)
    result.boxes = get_box_data(player)
    result.refreshTime = get_refresh_time()
    result.refreshNum = get_refresh_times(player)
    result.dungeonNum = get_fight_times(player)
    result.dungeonAdd = get_adtimes(player)
    result.dungeonStar = get_star_sum(player)
    result.diamondBuy = get_diamond_times(player)
    player:send_packet("MSGS2CArtifactStageData", result)
end
